﻿#pragma once

#include "Object/Object.h"
#include "Path/Path.h"
#include "Containers/ScriptDelegateImplement.h"
#include "Process.m.h"

class CProcessPlatformData;

RENUM()
enum class EProcessState
{
    NotRunning,
    Starting,
    Running,
};

RCLASS()
class WHENGINE_API RProcess : public RObject
{
    ROBJECT

public:
    RProcess();
    ~RProcess();

    //启动当前进程的子进程
    //子进程的会在当前进程的结束时自动结束
    void Start(
        const CString& Program
        ,const TVector<CString>& Arguments
        ,bool bReciveOutput=false
        ,bool bReciveError=false
    );

    //结束当前进程
    void Stop();

    //设置工作目录，需要在Start之前调用
    void SetWorkingDirectory(const SPath& InWorkingDirectory);
    SPath GetWorkingDirectory() const;

    // /// @brief 等待进程启动
    // /// @param Ms 等待时间，单位毫秒，默认为-1，表示无限等待
    // void WaitForStarted(int32_t Ms);

    /// @brief 等待进程结束
    /// @param Ms 等待时间，单位毫秒，默认为-1，表示无限等待
    void WaitForFinished(int64_t Ms);

    /// @brief 获取进程状态
    EProcessState GetState() const;

    /// @brief 获取进程ID
    uint64_t GetProcessId() const;

    /// @brief 进程结束时触发的事件
    TScriptDelegate<void(int64_t /*退出代码*/, bool /*是否正常退出*/ )> OnFinished;

    /// @brief 进程的标准输出时触发的事件,只有在bReciveOutput为true时才会触发
    ///由于底层使用了异步读取，所以这个事件需要应用处于运行状态才能触发(App->Run())
    TScriptDelegate<void()> OnStandardOutput;

    /// @brief 进程的标准错误输出时触发的事件，只有在bReciveError为true时才会触发
    ///断言也被输出到标准错误
    ///由于底层使用了异步读取，所以这个事件需要应用处于运行状态才能触发(App->Run())
    TScriptDelegate<void()> OnStandardError;

    //读取所有标准输出
    TVector<uint8_t> ReadAllStandardOutput();

    //读取所有标准错误
    ///断言也被输出到标准错误
    TVector<uint8_t> ReadAllStandardError();

    //通知有新的标准输出
    //这个函数由底层实现调用
    void NotifyStandardOutput(TVector<uint8_t>&& Data);

    //通知有新的标准错误
    //这个函数由底层实现调用
    void NotifyStandardError(TVector<uint8_t>&& Data);
protected:
    CProcessPlatformData* PlatformData=nullptr; 
    void CreatePlatformData();
    void DestroyPlatformData();

    EProcessState State=EProcessState::NotRunning;
    SPath WorkingDirectory;

    TVector<uint8_t> AllStandardOutput;
    TVector<uint8_t> AllStandardError;

    void StartReciveOutputTask();


    void StartReciveErrorTask();

    void StartDetecteTask();
};

